package cn.com.dcsgo.service.impl;

import cn.com.dcsgo.domain.ProdPropValue;
import cn.com.dcsgo.dto.*;
import cn.com.dcsgo.exception.BusinessException;
import cn.com.dcsgo.mapper.ProdPropValueMapper;
import cn.com.dcsgo.utils.AuthUtil;
import cn.com.dcsgo.vo.ProdPropVO;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.com.dcsgo.domain.ProdProp;
import cn.com.dcsgo.service.ProdPropService;
import cn.com.dcsgo.mapper.ProdPropMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 针对表【prod_prop(规格表)】的数据库操作Service实现
 *
 * @author Dcsgo
 * @since 2025-10-14 08:45:30
 */
@Slf4j
@Service
public class ProdPropServiceImpl extends ServiceImpl<ProdPropMapper, ProdProp>
        implements ProdPropService {

    @Resource
    private ProdPropValueMapper prodPropValueMapper;

    @Override
    public Page<ProdPropVO> getPage(PageDTO pageDTO, ProdPropQueryDTO prodPropQueryDTO) {
        // 要根据店铺查，超级店铺全都能看到
        // 规格查出来了，还要查规格的取值
        Page<ProdProp> propPage = new Page<>(pageDTO.getCurrent(), pageDTO.getSize());
        Long shopId = AuthUtil.getShopId();
        String propName = prodPropQueryDTO.getPropName();
        baseMapper.selectPage(
                propPage,
                new LambdaQueryWrapper<ProdProp>()
                        //shopID目前是可能为null的
                        .eq(shopId == null || !AuthUtil.getShopId().equals(1L), ProdProp::getShopId, shopId)
                        .like(StringUtils.hasText(propName), ProdProp::getPropName, propName)
        );
        // 返回的数据
        Page<ProdPropVO> propVOPage = new Page<>();
        BeanUtil.copyProperties(propPage, propVOPage, "records");
        // 注意records要特殊处理，因为 BeanUtil.copyProperties(propPage, propVOPage);
        // 只复制了 Page 本身的字段（current、size、total…），没有复制 records 列表里的元素，propVOPage.getRecords() 里仍然是原来的 ProdProp 对象。
        // 后续设置各个规格的规格值时就会报：
        // ClassCastException: class cn.com.dcsgo.domain.ProdProp cannot be cast to class cn.com.dcsgo.vo.ProdPropVO (cn.com.dcsgo.domain.ProdProp and cn.com.dcsgo.vo.ProdPropVO are in unnamed module of loader 'app')
        propVOPage.setRecords(propPage.getRecords().stream().map(prop -> {
            ProdPropVO propVO = new ProdPropVO();
            BeanUtil.copyProperties(prop, propVO);
            return propVO;
        }).collect(Collectors.toList()));
        // 用规格ID查规格值
        List<Long> propIdList = propPage.getRecords().stream().map(ProdProp::getPropId).toList();
        if (!CollectionUtils.isEmpty(propIdList)) {
            List<ProdPropValue> valueList = prodPropValueMapper.selectList(
                    new LambdaQueryWrapper<ProdPropValue>()
                            .in(ProdPropValue::getPropId, propIdList)
            );
            // 将规格值List转换成Map<规则ID,List<规格值>>
            Map<Long, List<ProdPropValue>> propValueMap = valueList.stream().collect(Collectors.groupingBy(ProdPropValue::getPropId));
            // 设置各个规格的规格值
            propVOPage.getRecords().forEach(propVo ->
                    propVo.setProdPropValues(propValueMap.get(propVo.getPropId()))
            );
        }
        return propVOPage;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean save(ProdPropAddDTO prodPropAddDTO) {
        Long shopId = AuthUtil.getShopId();
        if (shopId == null) {
            throw new BusinessException("请先关联店铺后，再进行操作");
        }
        //同一个店铺下的商品规格不能重复
        boolean exists = baseMapper.exists(
                new LambdaQueryWrapper<ProdProp>()
                        .eq(ProdProp::getShopId, shopId)
                        .eq(ProdProp::getPropName, prodPropAddDTO.getPropName())
        );
        if (exists) {
            throw new BusinessException("规格名称【" + prodPropAddDTO.getPropName() + "】已存在");
        }
        ProdProp saveProp = new ProdProp();
        saveProp.setShopId(shopId);
        saveProp.setPropName(prodPropAddDTO.getPropName());
        int row = baseMapper.insert(saveProp);
        //添加规格关联的规格值
        if (!CollectionUtils.isEmpty(prodPropAddDTO.getProdPropValues())) {
            //TODO: 当规格值较多时使用批量插入
            for (ProdPropValueAddDTO propValueAddDTO : prodPropAddDTO.getProdPropValues()) {
                ProdPropValue propValue = new ProdPropValue();
                propValue.setPropId(saveProp.getPropId());
                propValue.setPropValue(propValueAddDTO.getPropValue());
                row += prodPropValueMapper.insert(propValue);
            }
        }
        log.debug("ProdPropServiceImpl.save row:{}", row);
        return row > 0;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean update(ProdPropUpdateDTO prodPropUpdateDTO) {
        Long shopId = AuthUtil.getShopId();
        if (shopId == null) {
            throw new BusinessException("请先关联店铺后，再进行操作");
        }
        // 验证规格名在当前店铺下唯一
        ProdProp oldData = baseMapper.selectById(prodPropUpdateDTO.getPropId());
        if (oldData == null) {
            throw new BusinessException("规格不存在");
        }
        String newPropName = prodPropUpdateDTO.getPropName();
        if (newPropName != null && !oldData.getPropName().equals(newPropName)) {
            boolean exists = baseMapper.exists(
                    new LambdaQueryWrapper<ProdProp>()
                            .eq(ProdProp::getShopId, shopId)
                            .eq(ProdProp::getPropName, newPropName)
            );
            if (exists) {
                throw new BusinessException("规格名【" + newPropName + "】已存在");
            }
        }
        // 更新规格
        ProdProp updateData = new ProdProp();
        BeanUtil.copyProperties(prodPropUpdateDTO, updateData);
        int row = baseMapper.updateById(updateData);
        // 更新规格值
        if (prodPropUpdateDTO.getProdPropValues() != null) {
            // 删除旧的规格值
            row += prodPropValueMapper.delete(
                    new LambdaQueryWrapper<ProdPropValue>()
                            .eq(ProdPropValue::getPropId, prodPropUpdateDTO.getPropId())
            );
            // 添加新的规格值 TODO:规格值较多时使用批量插入
            for (ProdPropValueAddDTO propValueAddDTO : prodPropUpdateDTO.getProdPropValues()) {
                ProdPropValue propValue = new ProdPropValue();
                propValue.setPropId(prodPropUpdateDTO.getPropId());
                propValue.setPropValue(propValueAddDTO.getPropValue());
                row += prodPropValueMapper.insert(propValue);
            }
        }
        return row > 0;
    }

    @Override
    public boolean removePropAndValuesById(Long propId) {
        int row = baseMapper.deleteById(propId);
        row += prodPropValueMapper.delete(
                new LambdaQueryWrapper<ProdPropValue>()
                        .eq(ProdPropValue::getPropId, propId)
        );
        log.debug("ProdPropServiceImpl.removePropAndValuesById row:{}", row);
        return row > 0;
    }

    @Override
    public List<ProdProp> getAllProdPropByShopId(Long shopId) {
        if (shopId == null) {
            throw new BusinessException("请先关联店铺后再进行操作");
        }
        return baseMapper.selectList(
                new LambdaQueryWrapper<ProdProp>()
                        .eq(!shopId.equals(1L), ProdProp::getShopId, shopId)
        );
    }

    @Override
    public List<ProdPropValue> getPropValues(Long propId) {
        return prodPropValueMapper.selectList(
                new LambdaQueryWrapper<ProdPropValue>()
                        .eq(ProdPropValue::getPropId, propId)
        );
    }
}




